﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;
using System.Threading;
using System.IO;
using System.Windows.Forms;


namespace WBrowser
{
    public class RequestState
    {
        // This class stores the State of the request.
        const int BUFFER_SIZE = 1024;
        public StringBuilder requestData;
        public byte[] BufferRead;
        public HttpWebRequest request;
        public HttpWebResponse response;
        public Stream streamResponse;
        public RequestState()
        {
            BufferRead = new byte[BUFFER_SIZE];
            requestData = new StringBuilder("");
            request = null;
            streamResponse = null;
        }
    }

    public class ClientGetAsync
    {
        const int BUFFER_SIZE = 1024;
        const int CODEPAGE = 1252;
        const int DefaultTimeout = 2 * 60 * 1000; // 2 minutes timeout

        private ManualResetEvent _allDone = new ManualResetEvent(false);
        private Byte[] _buffer = new Byte[BUFFER_SIZE];
        private Encoding _enc = Encoding.GetEncoding(CODEPAGE);  // Windows default Code Page

        private string _url;
        private string _text;
        private string _id = "#";

        public ClientGetAsync(string url)
        {
            _url = url;
        }

        // Abort the request if the timer fires.
        private void TimeoutCallback(object state, bool timedOut)
        {
            if (timedOut)
            {
                HttpWebRequest request = state as HttpWebRequest;
                if (request != null)
                {
                    request.Abort();
                }
            }
        }

        public string GetIdNewThread()
        {
            try
            {
                //HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(_url);
                //myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback), myHttpWebRequest);
                //_allDone.WaitOne();

                // Create a HttpWebrequest object to the desired URL. 
                HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(_url);
                // Create an instance of the RequestState and assign the previous myHttpWebRequest
                // object to its request field.  
                RequestState myRequestState = new RequestState();
                myRequestState.request = myHttpWebRequest;

                // Start the asynchronous request.
                IAsyncResult result =
                  (IAsyncResult)myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback), myRequestState);

                // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
                ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), myHttpWebRequest, DefaultTimeout, true);

                // The response came in the allowed time. The work processing will happen in the 
                // callback function.
                _allDone.WaitOne();

                // Release the HttpWebResponse resource.
                myRequestState.response.Close();
            }
            catch (UriFormatException uriEx)
            {
                MessageBox.Show(uriEx.Message);
            }
            catch (HttpListenerException httpEx)
            {
                MessageBox.Show(httpEx.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            return _id;
        }

        public void RespCallback(IAsyncResult asynchronousResult)
        {
            //HttpWebRequest req = (HttpWebRequest)asynchronousResult.AsyncState;
            //HttpWebResponse resp = null;
            //Stream respstream = null;
            //try
            //{
            //    resp = (HttpWebResponse)req.EndGetResponse(Ar);
            //    respstream = resp.GetResponseStream();
            //    respstream.BeginRead(_buffer, 0, _buffer.Length, new AsyncCallback(ReadCallback), respstream);
            //}
            //catch (Exception e)
            //{
            //    if (resp != null)
            //        resp.Close();
            //    if (respstream != null)
            //        respstream.Close();
            //    _allDone.Set();
            //    MessageBox.Show(e.Message);
            //}

            try
            {
                // State of request is asynchronous.
                RequestState myRequestState = (RequestState)asynchronousResult.AsyncState;
                HttpWebRequest myHttpWebRequest = myRequestState.request;
                myRequestState.response = (HttpWebResponse)myHttpWebRequest.EndGetResponse(asynchronousResult);

                // Read the response into a Stream object.
                Stream responseStream = myRequestState.response.GetResponseStream();
                myRequestState.streamResponse = responseStream;

                // Begin the Reading of the contents of the HTML page and print it to the console.
                IAsyncResult asynchronousInputRead = responseStream.BeginRead(myRequestState.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), myRequestState);
                return;
            }
            catch (WebException e)
            {
                //Console.WriteLine("\nRespCallback Exception raised!");
                //Console.WriteLine("\nMessage:{0}", e.Message);
                //Console.WriteLine("\nStatus:{0}", e.Status);

                MessageBox.Show(e.Message);
            }
            _allDone.Set();
        }


        public void ReadCallBack(IAsyncResult asyncResult)
        {
            //Stream rs = (Stream)asyncResult.AsyncState;
            //int read = -1;
            //try
            //{
            //    read = rs.EndRead(asyncResult);
            //}
            //catch (Exception e)
            //{
            //    rs.Close();
            //    _allDone.Set();
            //    MessageBox.Show(e.Message);
            //}

            //if (read > 0)
            //{
            //    //If find then stop
            //    if (FindId(ref rs))
            //    {
            //        rs.Close();
            //        _allDone.Set();
            //        return;
            //    }
            //    //If Sync is complete then just search id
            //    if (asyncResult.CompletedSynchronously)
            //    {
            //        do
            //        {
            //            read = rs.Read(_buffer, 0, _buffer.Length);
            //            if (FindId(ref rs))
            //            {
            //                rs.Close();
            //                _allDone.Set();
            //                return;
            //            }
            //        }
            //        while (read > 0);
            //        rs.Close();
            //        _allDone.Set();
            //    }
            //    else
            //    {
            //        rs.BeginRead(_buffer, 0, _buffer.Length, new AsyncCallback(ReadCallback), rs);
            //    }
            //}
            //else
            //{
            //    if (read == 0)
            //    {
            //        // No More Data To Read.
            //        // Close The Response Stream To Free Up The Connection
            //        rs.Close();
            //        _allDone.Set();
            //    }
            //}

            try
            {
                RequestState myRequestState = (RequestState)asyncResult.AsyncState;
                Stream responseStream = myRequestState.streamResponse;
                int read = responseStream.EndRead(asyncResult);
                // Read the HTML page and then print it to the console.
                if (read > 0)
                {
                    //If find then stop
                    if (FindId(responseStream))
                    {
                        responseStream.Close();
                        _allDone.Set();
                        return;
                    }
                    myRequestState.requestData.Append(Encoding.ASCII.GetString(myRequestState.BufferRead, 0, read));
                    //If Sync is complete then just search id
                    if (asyncResult.CompletedSynchronously)
                    {
                        do
                        {
                            read = responseStream.Read(myRequestState.BufferRead, 0, BUFFER_SIZE);
                            if (FindId(responseStream))
                            {
                                responseStream.Close();
                                _allDone.Set();
                                return;
                            }
                        }
                        while (read > 0);
                        responseStream.Close();
                        _allDone.Set();
                    }
                    else
                    {
                        IAsyncResult asynchronousResult = responseStream.BeginRead(myRequestState.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), myRequestState);
                        return;
                    }
                }
                else
                {
                    //Console.WriteLine("\nThe contents of the Html page are : ");
                    //if (myRequestState.requestData.Length > 1)
                    //{
                    //    string stringContent;
                    //    stringContent = myRequestState.requestData.ToString();
                    //    Console.WriteLine(stringContent);
                    //}
                    //Console.WriteLine("Press any key to continue..........");
                    //Console.ReadLine();

                    responseStream.Close();
                }

            }
            catch (WebException e)
            {
                MessageBox.Show(e.Message);
            }
            _allDone.Set();
        }


        /// <summary>
        /// Find id new thread in stream
        /// </summary>
        /// <param name="rs"></param>
        /// <returns></returns>
        public bool FindId(Stream rs)
        {
            Regex rx = new Regex(@"newthread.php\?do=newthread&amp;(f=[0-9]+)");
            _text = GetStringFromByteArray(_buffer);

            Match m = rx.Match(_text);
            while (m.Success)
            {
                _id = m.Value.Replace("newthread.php?do=newthread&amp;f=", "");
                m = m.NextMatch();
            }

            //If find id thread then stop
            if (_id != "#")
                return true;

            return false;
        }

        /// <summary>
        /// Read text to byte[]
        /// </summary>
        /// <param name="sIn"></param>
        /// <returns></returns>
        public static byte[] GetByteArray(string sIn)
        {
            byte[] oTmp = new byte[sIn.Length];
            for (int i = 0; i < sIn.Length; i++)
            {
                oTmp[i] = (byte)(sIn.Substring(i, 1).ToCharArray(0, 1)[0]);
            }
            return oTmp;
        }


        /// <summary>
        /// Read byte to text
        /// </summary>
        /// <param name="oIn"></param>
        /// <returns></returns>
        public string GetStringFromByteArray(byte[] oIn)
        {
            Decoder d = Encoding.UTF8.GetDecoder();
            char[] charArray = new char[_enc.GetCharCount(oIn, 0, oIn.Length)];
            _enc.GetDecoder().GetChars(oIn, 0, oIn.Length, charArray, 0);
            string s = new string(charArray);
            return s;

            //string sTmp = "";
            //for (int i = 0; i < oIn.Length; i++)
            //{
            //    if (oIn[i] == 0) break;
            //    sTmp += ((char)oIn[i]).ToString();
            //}
            //return sTmp;
        }
    }
}
